/*
 * ﻿Copyright (C) 2009-2013 NewMain Softech
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package com.newmainsoftech.gwetons.client;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.gwt.core.client.JavaScriptException;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.DOM;
import com.newmainsoftech.gwetons.client.SimpleStyleProgressiveChanger.ChangeEventType;
import com.newmainsoftech.gwetons.client.SimpleStyleProgressiveChanger.CssRuleStyleAccessor;
import com.newmainsoftech.gwetons.client.SimpleStyleProgressiveChanger.ElementStyleAccessor;
import com.newmainsoftech.gwetons.client.logging.JsniLoggerWrap;
import com.newmainsoftech.gwetons.client.logging.JsniLoggerWrapFactoryInstanceHolder;
import com.newmainsoftech.gwetons.client.style.css.CssStyleChangerBySelector;
import com.newmainsoftech.gwetons.client.style.css.StyleChangerTimerEvent;
import com.newmainsoftech.gwetons.client.style.css.StyleChangerTimerEventManager;
import com.newmainsoftech.gwetons.client.timer.TimerControllerImpl;
import com.newmainsoftech.gwetons.logging.client.JsniLoggerWrapAdaptedGwtTestCase;
import com.newmainsoftech.gwetons.shared.logging.LoggerWrap;
import com.newmainsoftech.gwetons.shared.timer.TimerController;
import com.newmainsoftech.gwetons.shared.timer.TimerEventListener;

public class GwtTest_SimpleStyleProgressiveChanger extends JsniLoggerWrapAdaptedGwtTestCase {

	/**
	 * Must refer to a valid module that sources this class.
	 */
	public String getModuleName() {
		return "com.newmainsoftech.gwetons.GWeTons";
	}
	
	@Override
	protected String getNameForLogging() {
		return this.getClass().getName();
	}

	SimpleStyleProgressiveChanger simpleStyleProgressiveChanger;
	
	JsniLoggerWrap jsniLogUtil;
		LoggerWrap getLogUtil() {
			return jsniLogUtil.getLoggerWrap();
		}
	
	@Override
	public void gwtSetUp() {
		if ( jsniLogUtil == null) {
			getLoggerInitializerForTest().setupLogger();
			
			jsniLogUtil = getJsniLoggerWrap();
				jsniLogUtil.getLoggerWrap().getLogger().setLevel( Level.ALL);
				
			Logger otherLogger = Logger.getLogger( SimpleStyleProgressiveChanger.class.getName());
				otherLogger.setLevel( Level.ALL);
/*			otherLogger = Logger.getLogger( JsCssRule.class.getName());
				otherLogger.setLevel( Level.ALL);
			String packageName 
			= CssStyleChangerBySelector.class.getName()
				.substring( 0, CssStyleChangerBySelector.class.getName().lastIndexOf( "."));
				otherLogger = Logger.getLogger( packageName);
					otherLogger.setLevel( Level.ALL);
			packageName 
			= TimerControllerImpl.class.getName()
				.substring( 0, TimerControllerImpl.class.getName().lastIndexOf( "."));
				otherLogger = Logger.getLogger( packageName);
					otherLogger.setLevel( Level.ALL);
*/
		}
	}
	
	// fields to manage execution of test using delayTestFinish method to run one test at time in sequence
	private static int summedDelayByRunningTest = 0;
	private static long delayAddtionTime = (new Date()).getTime(); 
		static int getSummedDelayByRunningTest() {
			long currentTime = (new Date()).getTime();
			if ( currentTime > (delayAddtionTime + summedDelayByRunningTest)) {
				summedDelayByRunningTest = 0;
				delayAddtionTime = currentTime;
			}
			return summedDelayByRunningTest;
		}
		static void addToSummedDelayForRunningTest( int delay) {
			long currentTime = (new Date()).getTime();
			if ( currentTime > (delayAddtionTime + summedDelayByRunningTest)) {
				summedDelayByRunningTest = delay;
				delayAddtionTime = currentTime;
			}
			else {
				summedDelayByRunningTest = summedDelayByRunningTest + delay;
			}
		}
		static void subtractFromSummedDelayForRunningTest( int delay) {
			summedDelayByRunningTest = summedDelayByRunningTest - delay;
			if ( summedDelayByRunningTest < 0) {
				summedDelayByRunningTest = 0;
				delayAddtionTime = (new Date()).getTime();
			}
		}
		
	interface EventConfirmInterface extends TimerEventListener {
		String getTestName();
		boolean isEventConsumed();
		void consumeEvent();
		long getEnteringTime();
		void setEnteringTime( long enteringTime);
		int getExpectedPeriod();
		void setExpectedPeriod( int period);
	}
	// --------------------------------------------------------------------------------------------

	interface StyleAccessorDataIntf {
		public String getStyle();
		public String getCamelCaseStyle();

		public int getInitValue();
		public int getEndValue();

		public boolean isValueForColor();

		public String getRGBColorHexStr(int color);
		public int getDifferenceUnit();
		
		public int getPeriod();
		public void setPeriod(int period);

		public int getInterval();
		public void setInterval(int interval);
	}
	
	static class StyleAccessorDataWorker implements StyleAccessorDataIntf {
		LoggerWrap logUtil 
		= JsniLoggerWrapFactoryInstanceHolder
			.getJsniLoggerWrapFactory().getJsniLoggerWrap( this.getClass().getName()).getLoggerWrap();
			{
				logUtil.getLogger().setLevel( Level.ALL);
			};
		
		private final String style;
			public String getStyle() {
				return style;
			}
			public String getCamelCaseStyle() {
				if ( "z-index".equals( style)) return "zIndex";
				return style;
			}
		private final int initValue;
			public int getInitValue() {
				return initValue;
			}
		private final int endValue;
			public int getEndValue() {
				return endValue;
			}
		private final boolean isValueForColor;
			public boolean isValueForColor() {
				return isValueForColor;
			}
		public StyleAccessorDataWorker( 
				String style, int initValue, int endValue, boolean isValueForColor) {
			this.style = style;
			this.initValue = initValue;
			this.endValue = endValue;
			this.isValueForColor = isValueForColor;
		}
		
		private int period;
			public int getPeriod() {
				return period;
			}
			public void setPeriod( int period) {
				this.period = period;
			}
		private int interval;
			public int getInterval() {
				return interval;
			}
			public void setInterval(int interval) {
				this.interval = interval;
			}
		
		public String getRGBColorHexStr(int color) {
			String colorStr = Integer.toHexString( color);
			if ( colorStr.length() > 6) {
				colorStr = colorStr.substring( 0, 6);
			}
			else {
				String complementDigitStr = "0";
				if ( color < 0) complementDigitStr = "F";
				while( colorStr.length() < 6) {
					colorStr = complementDigitStr + colorStr;
				} // while
			}
			return colorStr;
		}

		public int getDifferenceUnit() {
			String methodName = "getDifferenceUnit";
			logUtil.entering( methodName, null);
			
			if ( isValueForColor) {
				String initValueHexStr = getRGBColorHexStr( initValue);
				String endValueHexStr = getRGBColorHexStr( endValue);
				String diffUnitStr = "";
				for( int index = 0; index < 3; index++) {
					String initOneColorSpectramStr = initValueHexStr.substring( index*2, index*2 + 2);
					String endOneColorSpectramStr = endValueHexStr.substring( index*2, index*2 + 2);
					int oneColorSpectramDiffUnit;
						if ( initValue < endValue) {
							oneColorSpectramDiffUnit
							= (Integer.parseInt( endOneColorSpectramStr, 16) 
									- Integer.parseInt( initOneColorSpectramStr, 16))*interval/period;
						}
						else {
							oneColorSpectramDiffUnit
							= (Integer.parseInt( initOneColorSpectramStr, 16) 
									- Integer.parseInt( endOneColorSpectramStr, 16))*interval/period;
						}
					String oneColorSpectramDiffUnitStr = Integer.toHexString( oneColorSpectramDiffUnit);
						if ( oneColorSpectramDiffUnitStr.length() < 2) {
							oneColorSpectramDiffUnitStr = "0" + oneColorSpectramDiffUnitStr;
						}
						else if ( oneColorSpectramDiffUnitStr.length() > 2) {
							oneColorSpectramDiffUnitStr 
							= oneColorSpectramDiffUnitStr.substring( 
									oneColorSpectramDiffUnitStr.length() - 2
									);
						}
					diffUnitStr = diffUnitStr + oneColorSpectramDiffUnitStr;
				} // for
				
				int differenceUnit = Integer.valueOf( diffUnitStr, 16);
					if ( initValue > endValue) {
						differenceUnit = differenceUnit * -1;
					}
				logUtil.exiting(methodName, differenceUnit);
				return differenceUnit;
			}
			else {
				int differenceUnit = (endValue - initValue)*interval/period;
				logUtil.exiting(methodName, differenceUnit);
				return differenceUnit;
			}
		}

	}
	
	enum StyleAccessorData implements StyleAccessorDataIntf {
		StyleEntry1( "styleEntry1", "color", 0, 0xecdc0e, true),
		StyleEntry2( "styleEntry2", "color", 0xecdc0e, 0, true),
		StyleEntry3( "styleEntry3", "z-index", 5000, 200, false);
		
		private final String id;
			public String getId() {
				return id;
			}
			public Element getDomElement() {
				Element element = Document.get().getElementById( id);
				if ( element == null) {
					element = DOM.createDiv();
						element.setId( id);
					Document.get().getBody().appendChild( element);
				}
				return element;
			}
		private StyleAccessorDataIntf styleAccessorDataIntf;
			private StyleAccessorDataIntf getStyleAccessorDataIntf() {
				return styleAccessorDataIntf;
			}

		StyleAccessorData( 
				String id, String style, int initValue, int endValue, boolean isValueForColor) 
		{
			this.id = id;
			styleAccessorDataIntf 
			= new StyleAccessorDataWorker( style, initValue, endValue, isValueForColor); 
		}
		// StyleAccessorDataIntf interface --------------------------------------------------------
		public String getStyle() {
			return getStyleAccessorDataIntf().getStyle();
		}
		public String getCamelCaseStyle() {
			return getStyleAccessorDataIntf().getCamelCaseStyle();
		}
		public int getInitValue() {
			return getStyleAccessorDataIntf().getInitValue();
		}
		public int getEndValue() {
			return getStyleAccessorDataIntf().getEndValue();
		}
		public boolean isValueForColor() {
			return getStyleAccessorDataIntf().isValueForColor();
		}
		public String getRGBColorHexStr( int color) {
			return getStyleAccessorDataIntf().getRGBColorHexStr( color);
		}
		public int getDifferenceUnit() {
			return getStyleAccessorDataIntf().getDifferenceUnit();
		}
		public int getPeriod() {
			return getStyleAccessorDataIntf().getPeriod();
		}
		public void setPeriod( int period) {
			getStyleAccessorDataIntf().setPeriod( period);
		}
		public int getInterval() {
			return getStyleAccessorDataIntf().getInterval();
		}
		public void setInterval( int interval) {
			getStyleAccessorDataIntf().setInterval( interval);
		}
		// ----------------------------------------------------------------------------------------
	}

	enum StyleAccessorType {
		DomIdStyleAccessor, ElementStyleAccessor;
	}
	
	class DoTest_addChangingStyleEntry implements EventConfirmInterface {
		private String testName;
			public String getTestName() {
				return testName;
			}
		int period;
			public int getExpectedPeriod() {
				return period;
			}
			public void setExpectedPeriod( int period) {
				this.period = period;
			}
		int delay;
		private StyleAccessorType styleAccessorType;
			public StyleAccessorType getStyleAccessorType() {
				return styleAccessorType;
			}
		
		public DoTest_addChangingStyleEntry( 
				String testName, int period, int delay, StyleAccessorType styleAccessorType) {
			this.testName = testName;
			this.period = period;
			this.delay = delay;
			this.styleAccessorType = styleAccessorType;
		}
		
		private boolean isEventConsumed = false;
			public boolean isEventConsumed() {
				return isEventConsumed;
			}
			public void consumeEvent() {
				isEventConsumed = true;
			}
			
		private long enteringTime;
			public long getEnteringTime() {
				return enteringTime;
			}
			public void setEnteringTime( long enteringTime) {
				this.enteringTime = enteringTime;
			}

		private EventConfirmInterface nextTestWorker;
			public EventConfirmInterface getNextTestWorker() {
				return nextTestWorker;
			}
			public void setNextTestWorker( EventConfirmInterface nextTestWorker) {
				this.nextTestWorker = nextTestWorker;
			}
		
		/**
		 * Create DIV elements being used for testing progressive style change, 
		 * add style entry changing data out of {@link StyleAccessorData} by 
		 * {@link SimpleStyleProgressiveChanger#addChangingStyleEntry} method, 
		 * and executes next task held by {@link #nextTestWorker} member field.
		 */
		public void fire() {
			if ( !isEventConsumed()) {
				setEnteringTime( (new Date()).getTime());
				
				consumeEvent();				
				
				LoggerWrap logUtil = getLogUtil();
				
				// Actual testing part ------------------------------------------------------------
				ArrayList<ElementStyleAccessor> styleAccessorArrayList 
				= new ArrayList<SimpleStyleProgressiveChanger.ElementStyleAccessor>();
				StyleAccessorData[] styleEntryDataArray 
				= StyleAccessorData.values();
				int styleAccessorLinkedHashSetSize 
				= simpleStyleProgressiveChanger.styleAccessorLinkedHashSet.size();
				for( StyleAccessorData styleEntryData : styleEntryDataArray) {
					logUtil.log( 
							Level.FINEST, 
							"Creating Div element for test data of " + styleEntryData.id
							);
					Element divElement = DOM.createDiv();
						divElement.setId( styleEntryData.id);
						Document.get().getBody().appendChild( divElement);
					
					logUtil.log( 
							Level.FINEST, 
							"Calling addChangingStyleEntry method to add test data of " 
							+ styleEntryData.id + " to simpleStyleProgressiveChanger.");
					if ( StyleAccessorType.DomIdStyleAccessor.equals( getStyleAccessorType())) {
						styleAccessorArrayList.add( 
								simpleStyleProgressiveChanger.addChangingStyleEntry( 
										styleEntryData.id, 
										styleEntryData.getCamelCaseStyle(), 
										styleEntryData.getInitValue(), 
										styleEntryData.getEndValue(), 
										styleEntryData.isValueForColor()
										)
								);
					}
					else {
						styleAccessorArrayList.add( 
								simpleStyleProgressiveChanger.addChangingStyleEntry( 
										styleEntryData.getDomElement(), 
										styleEntryData.getCamelCaseStyle(), 
										styleEntryData.getInitValue(), 
										styleEntryData.getEndValue(), 
										styleEntryData.isValueForColor()
										)
								);
					}
				} // for
				
				assertEquals( styleEntryDataArray.length, styleAccessorArrayList.size());
					boolean testResult
					= styleEntryDataArray.length == styleAccessorArrayList.size();
				assertEquals( 
						styleEntryDataArray.length, 
						(simpleStyleProgressiveChanger.styleAccessorLinkedHashSet.size() 
								- styleAccessorLinkedHashSetSize));
					testResult 
					= testResult 
							&& ( styleEntryDataArray.length 
									== ( simpleStyleProgressiveChanger.styleAccessorLinkedHashSet.size() 
											- styleAccessorLinkedHashSetSize));
				if ( testResult) {
					for( int index = 0; index < styleEntryDataArray.length; index++) {
						StyleAccessorData styleEntryData 
						= styleEntryDataArray[ index];
						ElementStyleAccessor styleAccessor = styleAccessorArrayList.get( index);
						logUtil.log( 
								Level.FINEST, 
								"Verifying initialization result of simpleStyleProgressiveChanger " 
								+ "after adding test data of " + styleEntryData.id
								);
						assertEquals( styleEntryData.id, styleAccessor.getElement().getId());
							testResult 
							= testResult && ( styleEntryData.id.equals( styleAccessor.getElement().getId()));
						assertEquals( styleEntryData.getCamelCaseStyle(), styleAccessor.getStyle());
							testResult 
							= testResult && 
							( styleEntryData.getCamelCaseStyle().equals( styleAccessor.getStyle()));
						assertEquals( styleEntryData.getInitValue(), styleAccessor.getInitValue());
							testResult 
							= testResult && ( styleEntryData.getInitValue() == styleAccessor.getInitValue());
						assertEquals( styleEntryData.getEndValue(), styleAccessor.getEndValue());
							testResult 
							= testResult && ( styleEntryData.getEndValue() == styleAccessor.getEndValue());
						assertEquals( styleEntryData.isValueForColor(), styleAccessor.isFlaggedAsValueForColor());
							testResult 
							= testResult 
							&& ( styleEntryData.isValueForColor() == styleAccessor.isFlaggedAsValueForColor());
						if ( !testResult) {
							break; // for
						}
					} // for
				}
				// --------------------------------------------------------------------------------
			
				long enteringTime = getEnteringTime();
				long endingTime = (new Date()).getTime();
				if ( getExpectedPeriod() < (endingTime - enteringTime)) {
					logUtil.log( 
							Level.SEVERE,
							("Until the part of calling simpleStyleProgressiveChanger" 
							+ ".addChangingStyleEntry for %1$s, it took %2$s[msec]; it's longer than " 
							+ "anticipated whole test duration %3$s[msec].")
							.replace( "%1$s", getTestName())
							.replace( "%2$s", String.valueOf( endingTime - enteringTime))
							.replace( "%3$s", String.valueOf( getExpectedPeriod()))
							);
				}
				else {
					logUtil.log( 
							Level.INFO,
							("Until the part of calling simpleStyleProgressiveChanger" 
							+ ".addChangingStyleEntry for %1$s, it elapsed %2$s[msec]. Whole test " 
							+ " duration is expected to be less than %3$s[msec].")
							.replace( "%1$s", getTestName())
							.replace( "%2$s", String.valueOf( endingTime - enteringTime))
							.replace( "%3$s", String.valueOf( getExpectedPeriod()))
							);
				}
				
				EventConfirmInterface nextTestWorker = getNextTestWorker();
				if (( nextTestWorker == null) || !testResult) {
					simpleStyleProgressiveChanger.cancelStyleChange();
						logUtil.log( 
								Level.INFO,
								"Canceled scheduled style changes for test data due " +
								"to failure in initialization of simpleStyleProgressiveChanger."
								);
					simpleStyleProgressiveChanger = null;
					GwtTest_SimpleStyleProgressiveChanger.subtractFromSummedDelayForRunningTest( delay);
					
					if ( testResult) {
						finishTest();
					}
					logUtil.exiting( getTestName());
				}
				else {
					nextTestWorker.setEnteringTime( getEnteringTime());
					nextTestWorker.fire();
				}
			}
		}
	}
	
	// Test with DomIdStyleChangerUnit type test data ---------------------------------------------
	public void test_addChangingStyleEntry_withStringIdArgument() {
		String methodName = getName() + " test";
		LoggerWrap logUtil = getLogUtil();
		logUtil.entering( methodName, null);
		
		if ( simpleStyleProgressiveChanger != null) {
			String message = "Other test seems to have not been finished yet.";
			fail( message);
			logUtil.log( Level.SEVERE, message);
			logUtil.exiting( methodName);
		}
		simpleStyleProgressiveChanger = new SimpleStyleProgressiveChanger( false, false);
		int period = 1500; //[msec]
		int summedDelayByRunningTest = GwtTest_SimpleStyleProgressiveChanger.getSummedDelayByRunningTest();
			if ( summedDelayByRunningTest < 10) {
				summedDelayByRunningTest = 10;
			}
		int delay = summedDelayByRunningTest + period;
		
		DoTest_addChangingStyleEntry testWorker
		= new DoTest_addChangingStyleEntry( 
				methodName, period, delay, StyleAccessorType.DomIdStyleAccessor);
		
		TimerController timerController = simpleStyleProgressiveChanger.getTimerController();
			timerController.schedule( testWorker, summedDelayByRunningTest);
			
		GwtTest_SimpleStyleProgressiveChanger.addToSummedDelayForRunningTest( delay);
		delayTestFinish( delay);
	}
	
	enum CheckOn {
		initValue, middleState, endValue;
	}
	class TestEndStubForDomIdStyleAccessorData implements EventConfirmInterface {
		private String testMethodName;
			public String getTestName() {
				return testMethodName;
			}
		private int testFinishDelay;
		private CheckOn checkOn;
		
		public TestEndStubForDomIdStyleAccessorData( 
				String testMethodName, int expectedWholeTestPeriod, int testFinishDelay, CheckOn checkOn) {
			this.testMethodName = testMethodName;
			this.period = expectedWholeTestPeriod;
			this.testFinishDelay = testFinishDelay;
			this.checkOn = checkOn;
		}

		private int period = -1;
			public int getExpectedPeriod() {
				return period;
			}
			public void setExpectedPeriod( int period) {
				this.period = period;
			}
		
		private long enteringTime = -1;
			public long getEnteringTime() {
				return enteringTime;
			}
			public void setEnteringTime( long enteringTime) {
				this.enteringTime = enteringTime;
			}
		
		List<TestEndStubForDomIdStyleAccessorData> endStubForStyleAccessorDataList;
			List<TestEndStubForDomIdStyleAccessorData> getEndStubForStyleAccessorDataList() {
				return endStubForStyleAccessorDataList;
			}
			void setEndStubForStyleAccessorDataList(
					List<TestEndStubForDomIdStyleAccessorData> endStubForStyleAccessorDataList) {
				this.endStubForStyleAccessorDataList = endStubForStyleAccessorDataList;
			}
			void cancelSiblings() {
				if ( getEndStubForStyleAccessorDataList() == null) return;
				
				LoggerWrap logUtil = getLogUtil();
				
				Iterator<TestEndStubForDomIdStyleAccessorData> endStubForStyleAccessorDataIterator 
				= getEndStubForStyleAccessorDataList().iterator();
				while( endStubForStyleAccessorDataIterator.hasNext()) {
					TestEndStubForDomIdStyleAccessorData endStubForDomIdStyleAccessorData
					= endStubForStyleAccessorDataIterator.next();
					if ( endStubForDomIdStyleAccessorData != this) {
						endStubForDomIdStyleAccessorData.consumeEvent();
					}
					
					simpleStyleProgressiveChanger
					.getTimerController().cancel( endStubForDomIdStyleAccessorData);
					
					logUtil.log( 
							Level.FINE, 
							"Caceled scheduled task %1$s of %2$s phase for %3$s."
							.replace( "%2$s", 
									(endStubForDomIdStyleAccessorData.isEventConsumed() 
											? "(what has been already finished)" 
											: "(what has not been performed yet)")
									)
							.replace( "%2$s", endStubForDomIdStyleAccessorData.checkOn.name())
							.replace( "%3$s", endStubForDomIdStyleAccessorData.getTestName())
							);
				}
			}

		private boolean isEventConsumed = false;
			public boolean isEventConsumed() {
				return isEventConsumed;
			}
			public void consumeEvent() {
				isEventConsumed = true;
			}

		private boolean testResult = true;
			public boolean getTestResult() {
				return testResult;
			}
			private void setTestResult( boolean testResult) {
				this.testResult = this.testResult && testResult;
			}
			
		public void fire() {
			if ( !isEventConsumed()) {
				LoggerWrap logUtil = getLogUtil();
				logUtil.log( Level.FINE, "Start confirming style change(s) for " + testMethodName);
				
				consumeEvent();
				
				StyleAccessorData[] styleEntryDataArray = StyleAccessorData.values();
				for( StyleAccessorData domIdStyleAccessorData : styleEntryDataArray) {
					String styleStr = domIdStyleAccessorData.getDomElement().getAttribute( "style");
						logUtil.log( 
								Level.FINE, 
								( "For %1$s phase, current style string of Div element of what id " 
								+ "is %2$s: %3$s.")
								.replace( "%1$s", checkOn.name())
								.replace( "%2$s", domIdStyleAccessorData.getId())
								.replace( "%3$s", styleStr)
								);
						assertTrue( 
								"Did not find " + domIdStyleAccessorData.getStyle() + " in style setting " 
								+ "of Div element of what id is " + domIdStyleAccessorData.id,
								styleStr.contains( domIdStyleAccessorData.getStyle()));
							setTestResult( styleStr.contains( domIdStyleAccessorData.getStyle()));
							if ( !getTestResult()) { 
								logUtil.log( Level.FINE, "Cancelling scheduled sibling test tasks.");
								cancelSiblings();
								break; // for
							}
							
							styleStr 
							= styleStr.substring( 
									styleStr.indexOf( domIdStyleAccessorData.getStyle()) 
									+ domIdStyleAccessorData.getStyle().length()
									);
							styleStr = styleStr.substring( styleStr.indexOf( ":") + 1);
							styleStr = styleStr.substring( 0, styleStr.indexOf( ";"));
							int styleStrLength = styleStr.length();
							styleStr = styleStr.substring( styleStr.indexOf( "#") + 1);
							int styleIntValue = -1;
								if ( styleStrLength != styleStr.length()) {
									styleStr = styleStr.trim();
									styleIntValue = Integer.parseInt( styleStr, 16);
								}
								else {
									styleStr = styleStr.trim();
									styleIntValue = Integer.parseInt( styleStr);
								}
						switch( checkOn) {
						case initValue:
							setTestResult( domIdStyleAccessorData.getInitValue() == styleIntValue);
							assertTrue(
									( "At %1$s phase, regarding Div element of what id is %2$s, " 
									+ "its style setting (%3$s) is not equals to the expected " 
									+ "initial value: %4$s:%5$s")
									.replace( "%1$s", checkOn.name())
									.replace( "%2$s", domIdStyleAccessorData.getId())
									.replace( "%3$s", 
											domIdStyleAccessorData.getDomElement().getAttribute( "style"))
									.replace( "%4$s", domIdStyleAccessorData.getStyle())
									.replace( "%5$s", 
											Integer.toHexString( domIdStyleAccessorData.getInitValue())),
									getTestResult()
									);
							break;
						case middleState:
							setTestResult( 
									(domIdStyleAccessorData.getInitValue() + domIdStyleAccessorData.getDifferenceUnit()) 
									== styleIntValue
									);
							assertTrue(
									( "At %1$s phase, regarding Div element of what id is %2$s, " 
									+ "its style setting (%3$s) does not contain %4$s:%5$s")
									.replace( "%1$s", checkOn.name())
									.replace( "%2$s", domIdStyleAccessorData.getId())
									.replace( "%3$s", 
											domIdStyleAccessorData.getDomElement().getAttribute( "style"))
									.replace( "%4$s", domIdStyleAccessorData.getStyle())
									.replace( "%5$s", 
											Integer.toHexString( 
													domIdStyleAccessorData.getInitValue()
													+ domIdStyleAccessorData.getDifferenceUnit()
													)
											),
									getTestResult()
									);
							break;
						case endValue:
							setTestResult( 
									Integer.toHexString( styleIntValue).compareTo( 
											Integer.toHexString( domIdStyleAccessorData.getEndValue())) >= 0
									);
							assertTrue(
									( "At %1$s phase, regarding Div element of what id is %2$s, " 
									+ "its style setting (%3$s) is not equal to %4$s:%5$s")
									.replace( "%1$s", checkOn.name())
									.replace( "%2$s", domIdStyleAccessorData.getId())
									.replace( "%3$s", 
											domIdStyleAccessorData.getDomElement().getAttribute( "style"))
									.replace( "%4$s", domIdStyleAccessorData.getStyle())
									.replace( "%5$s", 
											Integer.toHexString( domIdStyleAccessorData.getEndValue())),
									getTestResult()
									);
							break;
						} // switch
						if ( !getTestResult()) {
							logUtil.log( Level.FINE, "Cancelling scheduled sibling test tasks.");
							cancelSiblings();
							break; // for
						}
				} // for
				
				if ( !getTestResult() || CheckOn.endValue.equals( checkOn)) {
					GwtTest_SimpleStyleProgressiveChanger
					.subtractFromSummedDelayForRunningTest( testFinishDelay);
					if ( getTestResult()) {
						finishTest();
					}
					
					long enteringTime = getEnteringTime();
					long endingTime = (new Date()).getTime();
					if ( getExpectedPeriod() < (endingTime - enteringTime)) {
						logUtil.log( 
								Level.WARNING, 
								"%1$s test took %2$s[msec]; it's longer than expected %3$s[msec]"
								.replace( "%1$s", getTestName())
								.replace( "%2$s", String.valueOf( endingTime - enteringTime))
								.replace( "%3$s", String.valueOf( getExpectedPeriod()))
								);
					}
					
					logUtil.exiting( testMethodName);
				}
			}
		}
	}
	class DoTest_processStyleChange_withDomIdStyleAccessorData implements EventConfirmInterface {
		private String testName;
			public String getTestName() {
				return testName;
			}
		private int interval;
		private int period;
		private int wholeTestPeriod;
			public int getExpectedPeriod() {
				return wholeTestPeriod;
			}
			public void setExpectedPeriod(int period) {
				this.wholeTestPeriod = period;
			}
		private int delay;
		
		public DoTest_processStyleChange_withDomIdStyleAccessorData( 
				String testName, int interval, int period, int wholeTestPeriod, int delay) {
			this.testName = testName;
			this.interval = interval;
			this.period = period;
			this.wholeTestPeriod = wholeTestPeriod;
			this.delay = delay;
		}
		
		private boolean isEventConsumed = false;
			public boolean isEventConsumed() {
				return isEventConsumed;
			}
			public void consumeEvent() {
				isEventConsumed = true;
			}
			
		private long enteringTime;
			public long getEnteringTime() {
				return enteringTime;
			}
			public void setEnteringTime( long enteringTime) {
				this.enteringTime = enteringTime;
			}
		
		/**
		 * Initialize DOM element being used for testing with style value what is neither 
		 * initial value nor end value of test data, add {@link TestEndStubForDomIdStyleAccessorData} 
		 * instance for each phase of {@link CheckOn} to {@link TimerController} instance obtained 
		 * via {@link SimpleStyleProgressiveChanger#getTimerController()} method 
		 * on {@link #simpleStyleProgressiveChanger} member field in order to verify style change 
		 * at each phase, and start progressive style changes by calling 
		 * {@link SimpleStyleProgressiveChanger#processStyleChange()} method.
		 */
		public void fire() {
			if ( isEventConsumed()) return;
			consumeEvent();				
			
			LoggerWrap logUtil = getLogUtil();
			
			// Actual testing part ------------------------------------------------------------
			logUtil.log( 
					Level.FINEST, 
					"Initializing style of Div elements being used for testing.");
			StyleAccessorData[] styleEntryDataArray 
			= StyleAccessorData.values();
			for( StyleAccessorData domIdStyleAccessorData : styleEntryDataArray) {
				domIdStyleAccessorData.setInterval( interval);
				domIdStyleAccessorData.setPeriod( period);
				
				String styleValueStr;
				if ( domIdStyleAccessorData.getInitValue() < domIdStyleAccessorData.getEndValue()) {
					styleValueStr 
					= Integer.toHexString( 
							(domIdStyleAccessorData.getEndValue()-domIdStyleAccessorData.getInitValue())/2
							);
				}
				else {
					styleValueStr 
					= Integer.toHexString( 
							(domIdStyleAccessorData.getInitValue()-domIdStyleAccessorData.getEndValue())/2
							);
				}
				
				logUtil.log( 
						Level.FINEST, 
						"Initializing style of Div element of what id is " + domIdStyleAccessorData.getId() 
						+ " to " + styleValueStr + " (neither of initValue(=" 
						+ Integer.toHexString( domIdStyleAccessorData.getInitValue()) + ") nor endValue(=" 
						+ Integer.toHexString( domIdStyleAccessorData.getEndValue()) + "))");
				domIdStyleAccessorData.getDomElement()
				.setAttribute( 
						"style", domIdStyleAccessorData.getStyle().concat( ":").concat( styleValueStr));
					logUtil.log( 
							Level.FINEST, 
							"Style of DIV element (of what id is %1$s) is now %2$s."
							.replace( "%1$s", domIdStyleAccessorData.getId())
							.replace( "%2$s", domIdStyleAccessorData.getDomElement().getAttribute( "style"))
							);
			}
			
			TestEndStubForDomIdStyleAccessorData checkOnInitValue
			= new TestEndStubForDomIdStyleAccessorData( 
					testName, getExpectedPeriod(), delay, CheckOn.initValue);
				checkOnInitValue.setEnteringTime( getEnteringTime());
			TestEndStubForDomIdStyleAccessorData checkOnMiddleState
			= new TestEndStubForDomIdStyleAccessorData( 
					testName, getExpectedPeriod(), delay, CheckOn.middleState);
				checkOnMiddleState.setEnteringTime( getEnteringTime());
			TestEndStubForDomIdStyleAccessorData checkOnEndChange
			= new TestEndStubForDomIdStyleAccessorData( 
					testName, getExpectedPeriod(), delay, CheckOn.endValue);
				checkOnEndChange.setEnteringTime( getEnteringTime());
			
			ArrayList<TestEndStubForDomIdStyleAccessorData> endStubForStyleAccessorDataList
			= new ArrayList<TestEndStubForDomIdStyleAccessorData>();
				endStubForStyleAccessorDataList.add( checkOnInitValue);
				endStubForStyleAccessorDataList.add( checkOnMiddleState);
				endStubForStyleAccessorDataList.add( checkOnEndChange);
			
				checkOnInitValue.setEndStubForStyleAccessorDataList( endStubForStyleAccessorDataList);
				checkOnMiddleState.setEndStubForStyleAccessorDataList( endStubForStyleAccessorDataList);
				checkOnEndChange.setEndStubForStyleAccessorDataList( endStubForStyleAccessorDataList);
				
			logUtil.log( 
					Level.FINER, 
					( "Scheduling nexts tasks: 1) check initial state value at %1$s[msec] later, " 
					+ "2) check middle state vale at %2$s[msec] later, " 
					+ "3) check end state vale at %3$s[msec] later")
					.replace( "%1$s", String.valueOf( interval/2))
					.replace( "%2$s", String.valueOf( interval + interval/2))
					.replace( "%3$s", String.valueOf( period + interval/2))
					);
			TimerController timerController = simpleStyleProgressiveChanger.getTimerController();
				timerController.schedule( checkOnInitValue, interval/2);
				timerController.schedule( checkOnMiddleState, interval + interval/2);
				timerController.schedule( checkOnEndChange, period + interval/2);
			
			simpleStyleProgressiveChanger.processStyleChange();
				logUtil.log( 
						Level.FINER, 
						"simpleStyleProgressiveChanger.processStyleChange method has been executed.");
			
			long enteringTime = getEnteringTime();
			long endingTime = (new Date()).getTime();
			if ( getExpectedPeriod() < (endingTime - enteringTime)) {
				logUtil.log( 
						Level.SEVERE, 
						( "Until the part of calling simpleStyleProgressiveChanger" 
						+ ".processStyleChange method for %1$s, it took %2$s[msec]; it's longer " 
						+ "than anticipated whole test duration %3$s[msec].")
						.replace( "%1$s", getTestName())
						.replace( "%2$s", String.valueOf( endingTime - enteringTime))
						.replace( "%3$s", String.valueOf( getExpectedPeriod()))
						);
			}
			else {
				logUtil.log( 
						Level.INFO,
						( "Until the part of calling simpleStyleProgressiveChanger" 
						+ ".processStyleChange method for %1$s, it elapsed %2$s[msec]. Whole test " 
						+ " duration is expected to be less than %3$s[msec].")
						.replace( "%1$s", getTestName())
						.replace( "%2$s", String.valueOf( endingTime - enteringTime))
						.replace( "%3$s", String.valueOf( getExpectedPeriod()))
						);
			}
			// --------------------------------------------------------------------------------
		}
	}
	
	public void test_processStyleChange_withDomIdStyleAccessorData() {
		String methodName = getName() + " test";
		LoggerWrap logUtil = getLogUtil();
			logUtil.getLogger().setLevel( Level.ALL);
		logUtil.entering( methodName, null);
		
		if ( simpleStyleProgressiveChanger != null) {
			String message = "Other test seems to have not been finished yet.";
			fail( message);
			logUtil.log( Level.SEVERE, message);
			logUtil.exiting( methodName);
		}
		simpleStyleProgressiveChanger = new SimpleStyleProgressiveChanger( false, false);
			simpleStyleProgressiveChanger.setChangeEventType( ChangeEventType.OnceAtAll);
			
		int period = 5000; //[msec]
			assertTrue( simpleStyleProgressiveChanger.setPeriod( period));
		int interval = 2500; //[msec]
			assertTrue( simpleStyleProgressiveChanger.setInterval( interval));
		int testWorkerPeriod = period + interval * 2;
		int testLauncherPeriod = 1500;
		int wholeTestPeriod = testLauncherPeriod + testWorkerPeriod; //[msec]
		int summedDelayByRunningTest = GwtTest_SimpleStyleProgressiveChanger.getSummedDelayByRunningTest();
			if ( summedDelayByRunningTest < 10) {
				summedDelayByRunningTest = 10;
			}
		int delay = summedDelayByRunningTest + wholeTestPeriod;
			
		DoTest_processStyleChange_withDomIdStyleAccessorData testWorker
		= new DoTest_processStyleChange_withDomIdStyleAccessorData( 
				methodName, interval, period, wholeTestPeriod, delay);
		DoTest_addChangingStyleEntry testLauncher 
		= new DoTest_addChangingStyleEntry( 
				methodName, wholeTestPeriod, delay, StyleAccessorType.DomIdStyleAccessor);
			testLauncher.setNextTestWorker( testWorker);
		
		logUtil.log( 
				Level.FINEST, 
				"Actual test will be launched at about " 
				+ new Date((new Date()).getTime() + summedDelayByRunningTest).toString() 
				);
		TimerController timerController = simpleStyleProgressiveChanger.getTimerController();
			timerController.schedule( testLauncher, summedDelayByRunningTest);
		
		GwtTest_SimpleStyleProgressiveChanger.addToSummedDelayForRunningTest( delay);
		delayTestFinish( delay);
	}
	// --------------------------------------------------------------------------------------------
	
	// test on cancelStyleChange method -----------------------------------------------------------
	class EndStubForTest_cancelStyleChange extends TestEndStubForDomIdStyleAccessorData {
		public EndStubForTest_cancelStyleChange( 
				String testMethodName, int expectedWholeTestPeriod, int testFinishDelay) {
			super( testMethodName, expectedWholeTestPeriod, testFinishDelay, CheckOn.initValue);
		}
		
		@Override
		public void fire() {
			LoggerWrap logUtil = getLogUtil();
			
			super.fire();
			if ( super.getTestResult()) {
				GwtTest_SimpleStyleProgressiveChanger.subtractFromSummedDelayForRunningTest( 
						super.testFinishDelay);
				finishTest();
				logUtil.exiting( super.testMethodName);
			}
		}
	}
	class DoTest_cancelStyleChange implements EventConfirmInterface {
		private String testName;
			public String getTestName() {
				return testName;
			}
		private long enteringTime = -1;
			public long getEnteringTime() {
				return enteringTime;
			}
			public void setEnteringTime(long enteringTime) {
				this.enteringTime = enteringTime;
			}
		private int interval = -1;
		private int period = -1;
		private int wholeTestPeriod = -1;
			public int getExpectedPeriod() {
				return wholeTestPeriod;
			}
			public void setExpectedPeriod( int wholeTestPeriod) {
				this.wholeTestPeriod = wholeTestPeriod;
			}
		private int delay = -1;
		public DoTest_cancelStyleChange( 
				String testName, int interval, int period, int wholeTestPeriod, int delay) {
			this.testName = testName;
			this.interval = interval;
			this.period = period;
			this.wholeTestPeriod = wholeTestPeriod;
			this.delay = delay;
		}
		
		private boolean isEventConsumed = false;
			public boolean isEventConsumed() {
				return isEventConsumed;
			}
			public void consumeEvent() {
				isEventConsumed = true;
			}

		public void fire() {
			if ( isEventConsumed()) return;
			consumeEvent();				
			
			LoggerWrap logUtil = getLogUtil();
			
			// Actual testing part ------------------------------------------------------------
			logUtil.log( 
					Level.FINEST, 
					"Initializing style of Div elements being used for testing to empty string.");
				StyleAccessorData[] styleEntryDataArray 
				= StyleAccessorData.values();
				for( StyleAccessorData domIdStyleAccessorData : styleEntryDataArray) {
					domIdStyleAccessorData.setInterval( interval);
					domIdStyleAccessorData.setPeriod( period);
					
					logUtil.log( 
							Level.FINEST, 
							"Initializing style of Div element of what id is " + domIdStyleAccessorData.id
							+ " to empty string");
					domIdStyleAccessorData.getDomElement().setAttribute( "style", "");
				}
			
			EndStubForTest_cancelStyleChange endStubForTest_cancelStyleChange
			= new EndStubForTest_cancelStyleChange( getTestName(), getExpectedPeriod(), delay);
			
			TimerController timerController = simpleStyleProgressiveChanger.getTimerController();
				timerController.schedule( endStubForTest_cancelStyleChange, interval);
				
			logUtil.log( Level.FINER, "Calling processStyleChange method");
			simpleStyleProgressiveChanger.processStyleChange();
			
			long enteringTime = getEnteringTime();
			long endingTime = (new Date()).getTime();
			if ( getExpectedPeriod() < (endingTime - enteringTime)) {
				logUtil.log( 
						Level.SEVERE, 
						( "Until the part of calling simpleStyleProgressiveChanger.processStyleChange " 
						+ "method for %1$s, it took %2$s[msec]; it's longer than anticipated " 
						+ "whole test duration %3$s[msec].")
						.replace( "%1$s", getTestName())
						.replace( "%2$s", String.valueOf( endingTime - enteringTime))
						.replace( "%3$s", String.valueOf( getExpectedPeriod()))
						);
			}
			else {
				logUtil.log( 
						Level.INFO,
						( "Until the part of calling simpleStyleProgressiveChanger.processStyleChange " 
						+ "method for %1$s, it elapsed %2$s[msec]. Whole test duration is expected " 
						+ "to be less than %3$s[msec].")
						.replace( "%1$s", getTestName())
						.replace( "%2$s", String.valueOf( endingTime - enteringTime))
						.replace( "%3$s", String.valueOf( getExpectedPeriod()))
						);
			}
			// --------------------------------------------------------------------------------
		}
		
	}
	
	public void test_cancelStyleChange() {
		long enteringTime = (new Date()).getTime();
		String methodName = getName() + " test";
		LoggerWrap logUtil = getLogUtil();
		logUtil.entering( methodName, null);
		
		if ( simpleStyleProgressiveChanger != null) {
			String message = "Other test seems to have not been finished yet.";
			fail( message);
			logUtil.log( Level.SEVERE, message);
			logUtil.exiting( methodName);
		}
		simpleStyleProgressiveChanger = new SimpleStyleProgressiveChanger( false, false);
			simpleStyleProgressiveChanger.setChangeEventType( ChangeEventType.OnceAtAll);
			
		int period = 300; //[msec]
			assertTrue( simpleStyleProgressiveChanger.setPeriod( period));
		int interval = 150; //[msec]
			assertTrue( simpleStyleProgressiveChanger.setInterval( interval));
		int testWorkerPeriod = period + interval;
		int testLauncherPeriod = 400;
		int wholeTestPeriod = testLauncherPeriod + testWorkerPeriod; //[msec]
		int summedDelayByRunningTest = GwtTest_SimpleStyleProgressiveChanger.getSummedDelayByRunningTest();
			if ( summedDelayByRunningTest < 10) {
				summedDelayByRunningTest = 10;
			}
		int delay = summedDelayByRunningTest + wholeTestPeriod;
		
		DoTest_cancelStyleChange testWorker 
		= new DoTest_cancelStyleChange( methodName, interval, period, wholeTestPeriod, delay);
			testWorker.setEnteringTime( enteringTime);
		DoTest_addChangingStyleEntry testLauncher 
		= new DoTest_addChangingStyleEntry( 
				methodName, wholeTestPeriod, delay, StyleAccessorType.DomIdStyleAccessor);
			testLauncher.setNextTestWorker( testWorker);
			testLauncher.setEnteringTime( enteringTime);
		
		logUtil.log( 
				Level.FINEST, 
				"Actual test will be launched at about " 
				+ new Date((new Date()).getTime() + summedDelayByRunningTest).toString() 
				);
		TimerController timerController = simpleStyleProgressiveChanger.getTimerController();
			timerController.schedule( testLauncher, summedDelayByRunningTest);
		
		logUtil.log(
				Level.FINEST, 
				"Delaying finishing %1$s for %2$s[msec]."
				.replace( "%1$s", methodName)
				.replace( "%2$s", String.valueOf( delay))
				);
		GwtTest_SimpleStyleProgressiveChanger.addToSummedDelayForRunningTest( delay);
		delayTestFinish( delay);
	}
	// --------------------------------------------------------------------------------------------
	
	// Test with ElementStyleChangerUnit type test data ---------------------------------------------	
	public void test_addChangingStyleEntry_withElementArgument() {
		String methodName = getName() + " test";
		LoggerWrap logUtil = getLogUtil();
		logUtil.entering( methodName, null);
		
		if ( simpleStyleProgressiveChanger != null) {
			String message = "Other test seems to have not been finished yet.";
			fail( message);
			logUtil.log( Level.SEVERE, message);
			logUtil.exiting( methodName);
		}
		simpleStyleProgressiveChanger = new SimpleStyleProgressiveChanger( false, false);
		int period = 1000; //[msec]
		int summedDelayByRunningTest = GwtTest_SimpleStyleProgressiveChanger.getSummedDelayByRunningTest();
			if ( summedDelayByRunningTest < 10) {
				summedDelayByRunningTest = 10;
			}
		int delay = summedDelayByRunningTest + period;
		
		DoTest_addChangingStyleEntry testWorker
		= new DoTest_addChangingStyleEntry( 
				methodName, period, delay, StyleAccessorType.ElementStyleAccessor);

		TimerController timerController = simpleStyleProgressiveChanger.getTimerController();
			timerController.schedule( testWorker, summedDelayByRunningTest);
		
		GwtTest_SimpleStyleProgressiveChanger.addToSummedDelayForRunningTest( delay);
		delayTestFinish( delay);
	}
		
	public void test_processStyleChange_withElementStyleAccessorData() {
		String methodName = getName() + " test";
		LoggerWrap logUtil = getLogUtil();
		logUtil.entering( methodName, null);
		
		if ( simpleStyleProgressiveChanger != null) {
			String message = "Other test seems to have not been finished yet.";
			fail( message);
			logUtil.log( Level.SEVERE, message);
			logUtil.exiting( methodName);
		}
		simpleStyleProgressiveChanger = new SimpleStyleProgressiveChanger( false, false);
			simpleStyleProgressiveChanger.setChangeEventType( ChangeEventType.OnceAtAll);
			
		int period = 4000; //[msec]
			assertTrue( simpleStyleProgressiveChanger.setPeriod( period));
		int interval = 2000; //[msec]
			assertTrue( simpleStyleProgressiveChanger.setInterval( interval));
		int testWorkerPeriod = period + interval * 2;
		int testLauncherPeriod = 1000;
		int wholeTestPeriod = testLauncherPeriod + testWorkerPeriod; //[msec]
		int summedDelayByRunningTest = GwtTest_SimpleStyleProgressiveChanger.getSummedDelayByRunningTest();
			if ( summedDelayByRunningTest < 10) {
				summedDelayByRunningTest = 10;
			}
		int delay = summedDelayByRunningTest + wholeTestPeriod;
			
		DoTest_processStyleChange_withDomIdStyleAccessorData testWorker
		= new DoTest_processStyleChange_withDomIdStyleAccessorData( 
				methodName, interval, period, wholeTestPeriod, delay);
		DoTest_addChangingStyleEntry testLauncher 
		= new DoTest_addChangingStyleEntry( 
				methodName, wholeTestPeriod, delay, StyleAccessorType.ElementStyleAccessor);
			testLauncher.setNextTestWorker( testWorker);
		
		logUtil.log( 
				Level.FINEST, 
				"Actual test will be launched at about " 
				+ new Date((new Date()).getTime() + summedDelayByRunningTest).toString() 
				);
		TimerController timerController = simpleStyleProgressiveChanger.getTimerController();
			timerController.schedule( testLauncher, summedDelayByRunningTest);
		
		GwtTest_SimpleStyleProgressiveChanger.addToSummedDelayForRunningTest( delay);
		delayTestFinish( delay);
	}
	// --------------------------------------------------------------------------------------------
	
	// Test with CssRuleStyleChangerUnit type test data -------------------------------------------
	enum CssStyleAccessorData implements StyleAccessorDataIntf {
		NotUseThisSelector( "notUseThisSelector", "font-weight", 100, 600, false),
		StyleEntry1( "testStyleClass1", "color", 0, 0xecdc0e, true), 
		StyleEntry2( "testStyleClass2", "color", 0xecdc0e, 0, true), 
		StyleEntry3( "testStyleClass3", "z-index", 5000, 200, false);
		
		JsniLoggerWrap jsniLogUtil 
		=  JsniLoggerWrapFactoryInstanceHolder
			.getJsniLoggerWrapFactory().getJsniLoggerWrap( this.getClass().getName());
		LoggerWrap logUtil = jsniLogUtil.getLoggerWrap();
			{
				logUtil.getLogger().setLevel( Level.ALL);
			};
		
		private final String selector;
			public String getSelector() {
				return selector;
			}
			native void addCssRule( JsniLoggerWrap thisJsniLogUtil, String selector, String styleStr) 
			throws JavaScriptException /*-{
				// Preparations for logging ---------------------------------------------------------------
				var methodName = "addCssRule JSNI";
				var jsniLogEntering
				= thisJsniLogUtil.@com.newmainsoftech.gwetons.client.logging.JsniLoggerWrap::getEnteringFunction()();
				var jsniLogging
				= thisJsniLogUtil.@com.newmainsoftech.gwetons.client.logging.JsniLoggerWrap::getLogFunction()();
				var jsniLogExiting
				= thisJsniLogUtil.@com.newmainsoftech.gwetons.client.logging.JsniLoggerWrap::getExitingFunction()();
				// ----------------------------------------------------------------------------------------
				jsniLogEntering( methodName, null);
				
				var styleSheetPropertyIndex = 0;
				var styleSheetObj = $doc.styleSheets[ styleSheetPropertyIndex];
					var styleSheetPointerStr
					= @com.newmainsoftech.gwetons.client.style.css.CssStyleChangerBySelector::getStyleSheetPointer(I)( 
						styleSheetPropertyIndex);
				if ( styleSheetObj.desabled) {
					jsniLogging(
						@java.util.logging.Level::INFO,
						"Changing state of " + styleSheetPointerStr + " stylesheet to enabled from desabled."
						);
					styleSheetObj.desabled = false;
				}
						
				if ( styleSheetObj.addRule) { // IE
					styleSheetObj.addRule( selector, styleStr, -1);
					jsniLogging(
						@java.util.logging.Level::FINEST,
						"Added " + selector + "{" + styleStr + "} to " + styleSheetPointerStr + " style sheet."
						);
				}
				else if ( styleSheetObj.insertRule) { // Standard browser
					styleSheetObj.insertRule( 
						selector + "{" + styleStr + "}", styleSheetObj.cssRules.length);
					jsniLogging(
						@java.util.logging.Level::INFO,
						"Added " + selector + "{" + styleStr + "} to " + styleSheetPointerStr + " style sheet."
						);
				}
				else {
					jsniLogging(
						@java.util.logging.Level::SEVERE,
						"Failed to add " + selector + "{" + styleStr + "} to " + styleSheetPointerStr 
						+ " style sheet because could not detect neither addRule nor insertRule function."
						);
				}
				
				jsniLogExiting( methodName);
			}-*/;
			public JsCssRule getJsCssRule() {
				String methodName = "getJsCssRule";
				logUtil.entering( methodName, null);
				
				if ( !CssStyleChangerBySelector.sanityCheckStyleSheetsObj()) {
					logUtil.exiting( methodName, null);
					return null;
				}
				
//				prepRootStyleSheetMediaProperty( 0, jsniLogUtil);
				
				JsArray<JavaScriptObject> cssRuleArray 
				= CssStyleChangerBySelector.getCssRules( 
						getSelector(), 
						CssStyleChangerBySelector.DefaultSupportedStylesheetMediaTypeList.iterator(),
						true, false, false
						);
					logUtil.log(
							Level.FINEST,
							"Found " + ((cssRuleArray == null) ? "0" : cssRuleArray.length())
							+ " CSS rules with " + getSelector() + " selector in stylesheets."
							);
				boolean isCssRuleArraySubstantial = true;
					if ( cssRuleArray == null) isCssRuleArraySubstantial = false;
					else if ( cssRuleArray.length() < 1) isCssRuleArraySubstantial = false;
				if ( !isCssRuleArraySubstantial) {
					String testBaseStyle 
					= NotUseThisSelector.getStyle() + ":" + NotUseThisSelector.getInitValue();
					logUtil.log( 
							Level.FINEST, 
							"Creating CSS rule of " + getSelector() + "{" + testBaseStyle 
							+ "} in root stylesheet as test base."
							);
					addCssRule( jsniLogUtil, getSelector(), testBaseStyle);
					cssRuleArray 
					= CssStyleChangerBySelector.getCssRules( 
							getSelector(), 
							CssStyleChangerBySelector.DefaultSupportedStylesheetMediaTypeList.iterator(),
							true, false, false
							);
				}
				
				JsCssRule jsCssRule = new JsCssRule( cssRuleArray.get( 0));
				
				logUtil.exiting( methodName, jsCssRule);
				return jsCssRule;
			}
		private final StyleAccessorDataIntf styleAccessorDataIntf;
			private StyleAccessorDataIntf getStyleAccessorDataIntf() {
				return styleAccessorDataIntf;
			}
		CssStyleAccessorData( 
				String selector, String styleName, int initValue, int endValue, boolean isValueForColor) {
			this.selector = selector;
			styleAccessorDataIntf 
			= new StyleAccessorDataWorker( styleName, initValue, endValue, isValueForColor);
		}
		
		// StyleAccessorDataIntf interface --------------------------------------------------------
		public String getStyle() {
			return getStyleAccessorDataIntf().getStyle();
		}
		public String getCamelCaseStyle() {
			return getStyleAccessorDataIntf().getCamelCaseStyle();
		}
		public int getInitValue() {
			return getStyleAccessorDataIntf().getInitValue();
		}
		public int getEndValue() {
			return getStyleAccessorDataIntf().getEndValue();
		}
		public boolean isValueForColor() {
			return getStyleAccessorDataIntf().isValueForColor();
		}
		public String getRGBColorHexStr( int color) {
			return getStyleAccessorDataIntf().getRGBColorHexStr( color);
		}
		public int getDifferenceUnit() {
			return getStyleAccessorDataIntf().getDifferenceUnit();
		}
		public int getPeriod() {
			return getStyleAccessorDataIntf().getPeriod();
		}
		public void setPeriod( int period) {
			getStyleAccessorDataIntf().setPeriod( period);
		}
		public int getInterval() {
			return getStyleAccessorDataIntf().getInterval();
		}
		public void setInterval( int interval) {
			getStyleAccessorDataIntf().setInterval( interval);
		}
		// ----------------------------------------------------------------------------------------
	}
	class DoTest_addChangingStyleEntry_WithCssRuleStyleChangerUnitData extends DoTest_addChangingStyleEntry {

		public DoTest_addChangingStyleEntry_WithCssRuleStyleChangerUnitData( 
				String testName, int period, int delay) {
			super( testName, period, delay, null);
		}
		
		@Override
		public void fire() {
			if ( !isEventConsumed()) {
				setEnteringTime( (new Date()).getTime());
				
				consumeEvent();				
				
				LoggerWrap logUtil = getLogUtil();
				
				// Actual testing part ------------------------------------------------------------
				ArrayList<CssRuleStyleAccessor> styleAccessorArrayList 
				= new ArrayList<SimpleStyleProgressiveChanger.CssRuleStyleAccessor>();
				CssStyleAccessorData[] cssStyleAccessorDataArray = CssStyleAccessorData.values();
				int styleAccessorLinkedHashSetSize 
				= simpleStyleProgressiveChanger.styleAccessorLinkedHashSet.size();
				for( CssStyleAccessorData cssStyleAccessorData : cssStyleAccessorDataArray) {
					if ( CssStyleAccessorData.NotUseThisSelector.equals( cssStyleAccessorData)) {
						continue; // for 
					}
					logUtil.log( 
							Level.FINEST, 
							"Calling addChangingStyleEntry method to add test data of " 
							+ cssStyleAccessorData.getSelector() + " to simpleStyleProgressiveChanger.");
					
					styleAccessorArrayList.add( 
							simpleStyleProgressiveChanger.addChangingStyleEntry( 
									cssStyleAccessorData.getJsCssRule(), 
									cssStyleAccessorData.getStyle(), 
									cssStyleAccessorData.getInitValue(), 
									cssStyleAccessorData.getEndValue(), 
									cssStyleAccessorData.isValueForColor()
									)
							);
				} // for
				
				assertEquals( (cssStyleAccessorDataArray.length - 1), styleAccessorArrayList.size());
					boolean testResult
					= (cssStyleAccessorDataArray.length - 1) == styleAccessorArrayList.size();
				assertEquals( 
						(cssStyleAccessorDataArray.length - 1), 
						(simpleStyleProgressiveChanger.styleAccessorLinkedHashSet.size() 
								- styleAccessorLinkedHashSetSize));
					testResult 
					= testResult 
							&& ( (cssStyleAccessorDataArray.length - 1) 
									== ( simpleStyleProgressiveChanger.styleAccessorLinkedHashSet.size() 
											- styleAccessorLinkedHashSetSize));
				if ( testResult) {
					for( int index = 1; index < cssStyleAccessorDataArray.length; index++) {
						CssStyleAccessorData styleEntryData = cssStyleAccessorDataArray[ index];
						CssRuleStyleAccessor styleAccessor = styleAccessorArrayList.get( index - 1);
						logUtil.log( 
								Level.FINEST, 
								"Verifying result for test data of " + styleEntryData.getSelector());
						assertTrue(
								"Expected = " + styleEntryData.getSelector() 
								+ " but actual = " + styleAccessor.getCssRule().getSelectorText(),
								styleEntryData.getSelector()
								.equalsIgnoreCase( styleAccessor.getCssRule().getSelectorText()));
							testResult 
							= testResult && styleEntryData.getSelector()
											.equalsIgnoreCase( styleAccessor.getCssRule().getSelectorText());
						assertEquals( styleEntryData.getStyle(), styleAccessor.getStyle());
							testResult 
							= testResult && styleEntryData.getStyle().equals( styleAccessor.getStyle());
						assertEquals( styleEntryData.getInitValue(), styleAccessor.getInitValue());
							testResult 
							= testResult && ( styleEntryData.getInitValue() == styleAccessor.getInitValue());
						assertEquals( styleEntryData.getEndValue(), styleAccessor.getEndValue());
							testResult 
							= testResult && ( styleEntryData.getEndValue() == styleAccessor.getEndValue());
						assertEquals( styleEntryData.isValueForColor(), styleAccessor.isFlaggedAsValueForColor());
							testResult = testResult 
									&& ( styleEntryData.isValueForColor() 
											== styleAccessor.isFlaggedAsValueForColor());
						if ( !testResult) {
							break; // for
						}
					} // for
				}
				// --------------------------------------------------------------------------------
				
				long enteringTime = getEnteringTime();
				long endingTime = (new Date()).getTime();
				if ( getExpectedPeriod() < (endingTime - enteringTime)) {
					logUtil.log( 
							Level.SEVERE,
							("Until the part of calling simpleStyleProgressiveChanger" 
							+ ".addChangingStyleEntry for %1$s, it took %2$s[msec]; it's longer than " 
							+ "anticipated whole test duration %3$s[msec].")
							.replace( "%1$s", getTestName())
							.replace( "%2$s", String.valueOf( endingTime - enteringTime))
							.replace( "%3$s", String.valueOf( getExpectedPeriod()))
							);
				}
				else {
					logUtil.log( 
							Level.INFO,
							("Until the part of calling simpleStyleProgressiveChanger" 
							+ ".addChangingStyleEntry for %1$s, it elapsed %2$s[msec]. Whole test " 
							+ " duration is expected to be less than %3$s[msec].")
							.replace( "%1$s", getTestName())
							.replace( "%2$s", String.valueOf( endingTime - enteringTime))
							.replace( "%3$s", String.valueOf( getExpectedPeriod()))
							);
				}
				
				EventConfirmInterface nextTestWorker = getNextTestWorker();
				if (( nextTestWorker == null) || !testResult) {
simpleStyleProgressiveChanger.cancelStyleChange();
					simpleStyleProgressiveChanger = null;
					GwtTest_SimpleStyleProgressiveChanger.subtractFromSummedDelayForRunningTest( delay);
					
					if ( testResult) {
						finishTest();
					}
					logUtil.exiting( getTestName());
				}
				else {
					nextTestWorker.setEnteringTime( getEnteringTime());
					nextTestWorker.fire();
				}
			}
		}
	}
	
	public void test_addChangingStyleEntry_withJsCssRuleArgument() {
		String methodName = getName() + " test";
		LoggerWrap logUtil = getLogUtil();
		logUtil.entering( methodName, null);
		
		if ( simpleStyleProgressiveChanger != null) {
			String message = "Other test seems to have not been finished yet.";
			fail( message);
			logUtil.log( Level.SEVERE, message);
			logUtil.exiting( methodName);
		}
		simpleStyleProgressiveChanger = new SimpleStyleProgressiveChanger( false, false);
		int period = 9000; //[msec]
		int summedDelayByRunningTest = GwtTest_SimpleStyleProgressiveChanger.getSummedDelayByRunningTest();
			if ( summedDelayByRunningTest < 10) {
				summedDelayByRunningTest = 10;
			}
		int delay = summedDelayByRunningTest + period;
		
		DoTest_addChangingStyleEntry_WithCssRuleStyleChangerUnitData testWorker
		= new DoTest_addChangingStyleEntry_WithCssRuleStyleChangerUnitData( methodName, period, delay);
		
		TimerController timerController = simpleStyleProgressiveChanger.getTimerController();
			timerController.schedule( testWorker, summedDelayByRunningTest);
		
		GwtTest_SimpleStyleProgressiveChanger.addToSummedDelayForRunningTest( delay);
		delayTestFinish( delay);
	}
	// --------------------------------------------------------------------------------------------
}
